# Highlighted Search

**Category:** Features/Display/Highlighted Search

## Design

### Description

The searchable prop on table columns allows you to specify whether a column's content is included in search operations.
When a search is performed, matching text within searchable columns is automatically highlighted in the UI.

Simply add `searchable: true` to any column definition to enable search highlighting for that column.

### Example

Search by first name, last name, or level and see the results highlighted in the 2 first columns.

```tsx
import { Avatar } from '@wix/design-system';
import React from 'react';
import { CollectionPage } from '@wix/patterns/page';
import {
  OffsetQuery,
  Table,
  useTableCollection,
} from '@wix/patterns';
import { contacts } from '@wix/crm';

function Default() {

  const state = useTableCollection<contacts.Contact>({
    queryName: 'contacts-VisibleColumns',
    itemName: (item) => `${item.info?.name?.first} ${item.info?.name?.last}`,
    fetchData: (query: OffsetQuery) => {
      const { limit, offset, search, filters } = query;

      let queryBuilder = contacts.queryContacts().limit(limit).skip(offset);

      // Filter by search term in name and job title fields
      if (search && search.trim()) {
        // Filter locally after fetching since Wix contacts API has specific query limitations
        return queryBuilder.find().then(({ items = [], totalCount }) => {
          const searchTerm = search.toLowerCase();
          const filteredItems = items.filter(contact => {
            const firstName = contact.info?.name?.first?.toLowerCase() || '';
            const lastName = contact.info?.name?.last?.toLowerCase() || '';
            const fullName = `${firstName} ${lastName}`.trim();
            const jobTitle = contact.info?.jobTitle?.toLowerCase() || '';

            return fullName.includes(searchTerm) || jobTitle.includes(searchTerm);
          });

          return {
            items: filteredItems,
            total: filteredItems.length,
          };
        });
      }

      return queryBuilder.find().then(({ items = [], totalCount: total }) => ({
        items,
        total,
      }));
    },
    fetchErrorMessage: () => 'Error fetching contacts',
    filters: {},
  });

  return (
    <CollectionPage height="400px">
      <CollectionPage.Header title={{ text: 'Contacts' }} />
      <CollectionPage.Content>
        <Table
          state={state}
          columns={[
            {
              id: 'avatar',
              name: 'Avatar',
              title: '',
              width: '50px',
              render: (contact) => (
                <Avatar
                  name={`${contact.info?.name?.first} ${contact.info?.name?.last}`}
                  imgProps={{ src: contact.info?.picture?.image }}
                />
              ),
            },
            {
              id: 'name',
              title: 'Name',
              width: '250px',
              searchable: true, // Mark this column as searchable
              render: (contact) => `${contact.info?.name?.first} ${contact.info?.name?.last}`,
            },
            {
              id: 'level',
              title: 'Level',
              searchable: true, // Mark this column as searchable
              render: (contact) => contact.info?.jobTitle,
            },
            {
              id: 'lastActivity',
              title: 'Last Activity',
              render: (contact) =>
                contact.lastActivity?.activityDate?.toLocaleString(),
            },
          ]}
        />
      </CollectionPage.Content>
    </CollectionPage>
  );
}
```

